package com.fengze.shop.common.config;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import com.fengze.shop.common.cache.ConfigConstant;
import lombok.extern.slf4j.Slf4j;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

/**
 * 系统配置文件加载，并动态刷新
 */
@Slf4j
public class SystemConfig {


    private static SystemConfig instance = null;

    private static String configFile = null;

    private Document sysDocument = null;

    private Element sysElement = null;

    private List<ConfigDataListener> listeners = new Vector<ConfigDataListener>();

    public static SystemConfig getSystemConfig() {
        if (instance == null) {
            instance = new SystemConfig();
        }
        return instance;
    }

    private SystemConfig() {
        setConfigFile(ServerInfo.getSystemConfigFile());
    }

    public SystemConfig(String ConfigFile) {
        setConfigFile(ConfigFile);
    }

    public synchronized void addConfigDataListener(ConfigDataListener listener) {
        ConfigDataListener obj = getListener(listener.getListenerName());
        if (obj != null) {
            this.removeListener(listener.getListenerName());
        }
        listeners.add(listener);

        log.debug("Config listener added: {}  Class: {}", listener.getListenerName(), listener.getClass().getName());
    }

    public synchronized ConfigDataListener getListener(String listenerName) {
        ConfigDataListener listener = null;
        for (int i = 0; i < listeners.size(); i++) {
            listener = listeners.get(i);
            String temp = listener.getListenerName();
            if (temp.equals(listenerName)) {
                return listener;
            }
        }
        return null;
    }

    public synchronized void removeListener(String listenerName) {
        ConfigDataListener listener = null;
        for (int i = 0; i < listeners.size(); i++) {
            listener = listeners.get(i);
            String temp = listener.getListenerName();
            if (temp.equals(listenerName)) {
                listeners.remove(i);
            }
        }
    }

    private void doRefresh() {
        ConfigDataListener listener = null;
        int size = listeners.size();
        for (int i = 0; i < size; i++) {
            try {
                listener = listeners.get(i);
                log.debug("Listener Name = {} Start doRefresh", listener.getListenerName());

                listener.doConfigRefresh();

                log.debug("Listener Name = {} doRefresh End!", listener.getListenerName());
            } catch (Throwable ex) {
                log.error("Config Listener doConfigFresh Error!", ex);
            }
        }
    }


    public ModuleConfig getModuleConfig(String moduleName) {
        checkConfig(moduleName);
        ModuleConfig mConfig = null;
        String tempName = null;
        if (sysElement == null) {
            this.load();
        }
        List list = sysElement.getChildren(ConfigConstant.MODULE_CONFIG);
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            Element element = (Element) iterator.next();
            tempName = element.getAttribute(ConfigConstant.NAME).getValue();
            if (tempName.equalsIgnoreCase(moduleName)) {
                mConfig = new ModuleConfig(element);
                break;
            }
        }
        return mConfig;
    }

    private void checkConfig(String moduleName) {
        if (sysDocument == null || sysElement == null) {
            load();
            return;
        }
        List list = sysElement.getChildren(ConfigConstant.MODULE_CONFIG);
        if (list == null) {
            load();
        }
    }


    public synchronized void load() {
        try {
            SAXBuilder builder = new SAXBuilder();
            log.debug("Load config file: {}", configFile);
            sysDocument = builder.build(configFile);
            sysElement = sysDocument.getRootElement();
            this.doRefresh();
        } catch (Exception ex) {
            log.error("Load SystemConfig Error! {} ", ex);
        }
    }


    private synchronized void save2File() {
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(configFile);
            XMLOutputter xmlOutputter = new XMLOutputter();
            Format format = Format.getPrettyFormat();
            format.setEncoding("GB2312");
            xmlOutputter.setFormat(format);
            xmlOutputter.output(sysDocument, out);
            this.doRefresh();
        } catch (IOException ex) {
            log.error("Save Config to File Error!", ex);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (Exception e) {
                    log.error("FileOutputStream Close Error!", e);
                }
            }
        }
    }


    public ModuleConfig[] getModuleConfigs() {
        ModuleConfig[] mConfigs = null;
        List list = sysElement.getChildren("ModuleConfig");
        mConfigs = new ModuleConfig[list.size()];
        Iterator iterator = list.iterator();
        int i = 0;
        while (iterator.hasNext()) {
            Element element = (Element) iterator.next();
            mConfigs[i++] = new ModuleConfig(element);
        }
        return mConfigs;
    }


    public synchronized boolean addModuleConfig(ModuleConfig module) {
        if (this.getModuleConfig(module.getModuleName()) != null) {
            return false;
        } else {
            sysElement.addContent(module.getElement());
            this.save2File();
            return true;
        }
    }


    public synchronized void removeModuleConfig(String moduleName) {
        ModuleConfig mcfg = this.getModuleConfig(moduleName);
        if (mcfg == null) {
            return;
        }
        sysElement.removeContent(mcfg.getElement());
        this.save2File();
    }


    public synchronized void modifyItem(String moduleName, Item item) {
        ModuleConfig mcfg = this.getModuleConfig(moduleName);
        if (log.isDebugEnabled()) {
            log.debug("Name=" + item.getName());
            log.debug("Description=" + item.getDescription());
            log.debug("Value=" + item.getValue());
        }
        mcfg.getItem(item.getName()).modify(item);
        this.save2File();
    }


    public synchronized void modifyArrayItem(String moduleName, ArrayItem aItem) {
        ModuleConfig mcfg = this.getModuleConfig(moduleName);
        mcfg.getArrayItem(aItem.getName()).modify(aItem);
        this.save2File();
    }


    public synchronized boolean addItem(String moduleName, Item item) {
        ModuleConfig mcfg = this.getModuleConfig(moduleName);
        if (mcfg.getItem(item.getName()) != null) {
            return false;
        } else {
            mcfg.getElement().addContent(item.getElement());
            this.save2File();
            return true;
        }
    }


    public synchronized boolean addArrayItem(String moduleName, ArrayItem aitem) {
        ModuleConfig mcfg = this.getModuleConfig(moduleName);
        if (mcfg.getItem(aitem.getName()) != null) {
            return false;
        } else {
            mcfg.getElement().addContent(aitem.getElement());
            this.save2File();
            return true;
        }
    }


    public synchronized void removeItem(String moduleName, String itemName) {
        ModuleConfig mcfg = this.getModuleConfig(moduleName);
        Item item = mcfg.getItem(itemName);
        if (item != null) {
            mcfg.removeItem(itemName);
        } else {
            mcfg.removeArrayItem(itemName);
        }
        this.save2File();
    }


    protected Document getDocument() {
        return sysDocument;
    }

    public String getConfigFile() {
        return configFile;
    }

    public static void setConfigFile(String configFile) {
        SystemConfig.configFile = configFile;
    }

}
